Skip to content

bug(spec-specs, tests): EIP-8037 strict block-gas inclusion rule#2892

Merged
spencer-tb merged 4 commits into
ethereum:forks/amsterdamfrom
chfast:feat/eip-8037-block-gas-inclusion-strict
Jun 16, 2026
Merged

bug(spec-specs, tests): EIP-8037 strict block-gas inclusion rule#2892
spencer-tb merged 4 commits into
ethereum:forks/amsterdamfrom
chfast:feat/eip-8037-block-gas-inclusion-strict

Conversation

@chfast

@chfast chfast commented May 21, 2026

Copy link
Copy Markdown
Member

🗒️ Description

EIP-8037 specifies the per-dimension inclusion check at block start as:

min(TX_MAX_GAS_LIMIT, tx.gas) <= regular_gas_available
tx.gas <= state_gas_available

EELS Amsterdam was subtracting intrinsic.state / intrinsic.regular from tx.gas in each dimension, which let a transaction with non-zero state intrinsic (CREATE, EIP-7702 set_code) be included when tx.gas exceeded block.gas_limit by up to intrinsic.regular (state-dim) or intrinsic.state (regular-dim). evmone, revm, and erigon enforce the EIP literally and reject; pre-bump geth rejects too.

Add a parametrized test under EIP-8037 covering the boundary across all post-EIP-7702 tx types and contract-creation kinds, at two block-gas-limit values to avoid hard-coded-cap false-positives.

🔗 Related Issues or PRs

N/A.

✅ Checklist

  • All: Ran fast static checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    just static
  • All: PR title adheres to the repo standard - it will be used as the squash commit message and should start type(scope):.
  • All: Considered updating the online docs in the ./docs/ directory.
  • All: Set appropriate labels for the changes (only maintainers can apply labels).
  • Tests: Ran mkdocs serve locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.
  • Tests: For PRs implementing a missed test case, update the post-mortem document to add an entry the list.

@marioevz

Copy link
Copy Markdown
Member

We are in the process of merging EIP-8037 to forks/amsterdam via this PR: #2901

Once the PR is merged we can point this to the forks/amsterdam branch and then merge.

chfast added a commit to ipsilon/evmone that referenced this pull request Jun 2, 2026
EIP-8037 §"Transaction validation" rule 2 requires a per-tx inclusion
check against the per-dimension remaining budget:

    min(TX_MAX_GAS_LIMIT, tx.gas) <= regular_gas_available
    tx.gas <= state_gas_available

Add `state_block_gas_left` parameter to `validate_transaction` and
enforce both checks for Amsterdam+; default to 0 in the header for
pre-Amsterdam call sites that ignore state-gas. Errors are
`GAS_LIMIT_REACHED` (mapped to `TransactionException.GAS_ALLOWANCE_EXCEEDED`
by EEST).

Also flip the existing Amsterdam intrinsic-cap check from
`GAS_LIMIT_EXCEEDS_MAXIMUM` to `INTRINSIC_GAS_TOO_LOW`: EELS raises
`InsufficientTransactionGasError` here ("the tx can't pay its
intrinsic within the reservoir bound"), not the EIP-7825 absolute-cap
exception.

Note on EELS divergence: amsterdam/fork.py:561-583 currently subtracts
intrinsic.state / intrinsic.regular from tx.gas in each dimension
(`min(TX_MAX_GAS_LIMIT, tx.gas - intrinsic.state)` etc.), which is
more permissive than the EIP. ethereum/execution-specs#2892 aligns
EELS back with the EIP literal. This implementation follows the EIP
text directly — same as revm/erigon/pre-bump-geth.

`test::transition` (the TestState wrapper used by state-transition
unit tests and state tests) passes `block_gas_left` as both budgets,
since those tests run a single tx in a fresh block.

evmone-unittests: 1116 / 1116 pass.
chfast added a commit to ipsilon/evmone that referenced this pull request Jun 8, 2026
EIP-8037 §"Transaction validation" rule 2 requires a per-tx inclusion
check against the per-dimension remaining budget:

    min(TX_MAX_GAS_LIMIT, tx.gas) <= regular_gas_available
    tx.gas <= state_gas_available

Add `state_block_gas_left` parameter to `validate_transaction` and
enforce both checks for Amsterdam+; default to 0 in the header for
pre-Amsterdam call sites that ignore state-gas. Errors are
`GAS_LIMIT_REACHED` (mapped to `TransactionException.GAS_ALLOWANCE_EXCEEDED`
by EEST).

Also flip the existing Amsterdam intrinsic-cap check from
`GAS_LIMIT_EXCEEDS_MAXIMUM` to `INTRINSIC_GAS_TOO_LOW`: EELS raises
`InsufficientTransactionGasError` here ("the tx can't pay its
intrinsic within the reservoir bound"), not the EIP-7825 absolute-cap
exception.

Note on EELS divergence: amsterdam/fork.py:561-583 currently subtracts
intrinsic.state / intrinsic.regular from tx.gas in each dimension
(`min(TX_MAX_GAS_LIMIT, tx.gas - intrinsic.state)` etc.), which is
more permissive than the EIP. ethereum/execution-specs#2892 aligns
EELS back with the EIP literal. This implementation follows the EIP
text directly — same as revm/erigon/pre-bump-geth.

`test::transition` (the TestState wrapper used by state-transition
unit tests and state tests) passes `block_gas_left` as both budgets,
since those tests run a single tx in a fresh block.

evmone-unittests: 1116 / 1116 pass.
@chfast chfast force-pushed the feat/eip-8037-block-gas-inclusion-strict branch from 3e7af72 to 8649d8c Compare June 10, 2026 07:55
@chfast chfast changed the base branch from devnets/bal/7 to forks/amsterdam June 10, 2026 07:57

@misilva73 misilva73 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the correct check is the current EIP version and this PR aligns the execution specs with the EIP. So I think we should merge it.

We discussed this some time ago and decided to do this simpler check instead of the one currently in EELS

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.28%. Comparing base (0a4030b) to head (8b8f077).

Additional details and impacted files
@@                 Coverage Diff                 @@
##           forks/amsterdam    #2892      +/-   ##
===================================================
- Coverage            81.28%   81.28%   -0.01%     
===================================================
  Files                  620      620              
  Lines                36643    36641       -2     
  Branches              3311     3311              
===================================================
- Hits                 29786    29784       -2     
  Misses                6335     6335              
  Partials               522      522              
Flag Coverage Δ
unittests 81.28% <100.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

chfast added a commit to ipsilon/evmone that referenced this pull request Jun 12, 2026
EIP-8037 §"Transaction validation" rule 2 requires a per-tx inclusion
check against the per-dimension remaining budget:

    min(TX_MAX_GAS_LIMIT, tx.gas) <= regular_gas_available
    tx.gas <= state_gas_available

Add `state_block_gas_left` parameter to `validate_transaction` and
enforce both checks for Amsterdam+; default to 0 in the header for
pre-Amsterdam call sites that ignore state-gas. Errors are
`GAS_LIMIT_REACHED` (mapped to `TransactionException.GAS_ALLOWANCE_EXCEEDED`
by EEST).

Also flip the existing Amsterdam intrinsic-cap check from
`GAS_LIMIT_EXCEEDS_MAXIMUM` to `INTRINSIC_GAS_TOO_LOW`: EELS raises
`InsufficientTransactionGasError` here ("the tx can't pay its
intrinsic within the reservoir bound"), not the EIP-7825 absolute-cap
exception.

Note on EELS divergence: amsterdam/fork.py:561-583 currently subtracts
intrinsic.state / intrinsic.regular from tx.gas in each dimension
(`min(TX_MAX_GAS_LIMIT, tx.gas - intrinsic.state)` etc.), which is
more permissive than the EIP. ethereum/execution-specs#2892 aligns
EELS back with the EIP literal. This implementation follows the EIP
text directly — same as revm/erigon/pre-bump-geth.

`test::transition` (the TestState wrapper used by state-transition
unit tests and state tests) passes `block_gas_left` as both budgets,
since those tests run a single tx in a fresh block.

evmone-unittests: 1116 / 1116 pass.

@spencer-tb spencer-tb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM. Adding 2 small nits to preserve state/regular in exception message.

Comment thread src/ethereum/forks/amsterdam/fork.py Outdated
Comment thread src/ethereum/forks/amsterdam/fork.py Outdated
chfast and others added 4 commits June 16, 2026 12:35
EIP-8037 specifies the per-dimension inclusion check at block start as:

    min(TX_MAX_GAS_LIMIT, tx.gas) <= regular_gas_available
    tx.gas <= state_gas_available

EELS Amsterdam was subtracting intrinsic.state / intrinsic.regular from
tx.gas in each dimension, which let a transaction with non-zero state
intrinsic (CREATE, EIP-7702 set_code) be included when tx.gas exceeded
block.gas_limit by up to intrinsic.regular (state-dim) or intrinsic.state
(regular-dim). evmone, revm, and erigon enforce the EIP literally and
reject; pre-bump geth rejects too.

Add a parametrized test under EIP-8037 covering the boundary across all
post-EIP-7702 tx types and contract-creation kinds, at two block-gas-limit
values to avoid hard-coded-cap false-positives.
The strict per-dimension inclusion rule checks
`min(TX_MAX_GAS_LIMIT, tx.gas) <= regular_gas_available` and
`tx.gas <= state_gas_available` (no intrinsic subtraction). Update the
five tests in test_state_gas_reservoir.py that encoded the old
subtracting formula:

- test_block_state_gas_limit_boundary: size tx2 at `state_available`.
- test_creation_tx_regular_check_subtracts_intrinsic_state -> renamed
  test_creation_tx_regular_check_uses_full_tx_gas, now asserts the
  creation tx is rejected (no `intrinsic.state` subtraction).
- test_block_2d_gas_valid_when_cumulative_exceeds_limit: size num_txs
  by the binding state dimension so all txs are includable.
- test_single_tx_state_check_exceeds_block_limit,
  test_creation_tx_state_check_exceeded: drop subtracting-formula
  framing from docstrings, sizing, and assertions.
@spencer-tb spencer-tb force-pushed the feat/eip-8037-block-gas-inclusion-strict branch from 1a80ba2 to 8b8f077 Compare June 16, 2026 11:40
@spencer-tb spencer-tb added A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) C-feat Category: an improvement or new feature P-high A-tests Area: Consensus tests. C-bug Category: this is a bug, deviation, or other problem labels Jun 16, 2026
@spencer-tb spencer-tb changed the title fix(spec-specs, tests): EIP-8037 strict block-gas inclusion rule bug(spec-specs, tests): EIP-8037 strict block-gas inclusion rule Jun 16, 2026
@spencer-tb

Copy link
Copy Markdown
Contributor

Will merge once CI passes! Thx :)

@spencer-tb spencer-tb merged commit 90e74f1 into ethereum:forks/amsterdam Jun 16, 2026
26 checks passed
chfast added a commit to ipsilon/evmone that referenced this pull request Jun 18, 2026
EIP-8037 §"Transaction validation" rule 2 requires a per-tx inclusion
check against the per-dimension remaining budget:

    min(TX_MAX_GAS_LIMIT, tx.gas) <= regular_gas_available
    tx.gas <= state_gas_available

Add `state_block_gas_left` parameter to `validate_transaction` and
enforce both checks for Amsterdam+; default to 0 in the header for
pre-Amsterdam call sites that ignore state-gas. Errors are
`GAS_LIMIT_REACHED` (mapped to `TransactionException.GAS_ALLOWANCE_EXCEEDED`
by EEST).

Also flip the existing Amsterdam intrinsic-cap check from
`GAS_LIMIT_EXCEEDS_MAXIMUM` to `INTRINSIC_GAS_TOO_LOW`: EELS raises
`InsufficientTransactionGasError` here ("the tx can't pay its
intrinsic within the reservoir bound"), not the EIP-7825 absolute-cap
exception.

Note on EELS divergence: amsterdam/fork.py:561-583 currently subtracts
intrinsic.state / intrinsic.regular from tx.gas in each dimension
(`min(TX_MAX_GAS_LIMIT, tx.gas - intrinsic.state)` etc.), which is
more permissive than the EIP. ethereum/execution-specs#2892 aligns
EELS back with the EIP literal. This implementation follows the EIP
text directly — same as revm/erigon/pre-bump-geth.

`test::transition` (the TestState wrapper used by state-transition
unit tests and state tests) passes `block_gas_left` as both budgets,
since those tests run a single tx in a fresh block.

evmone-unittests: 1116 / 1116 pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-spec-specs Area: Specification—The Ethereum specification itself (eg. `src/ethereum/*`) A-tests Area: Consensus tests. C-bug Category: this is a bug, deviation, or other problem C-feat Category: an improvement or new feature P-high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants